#ifndef OWN_THUNK_THIS_TO_STDCALL_H_080322
#define OWN_THUNK_THIS_TO_STDCALL_H_080322

#include <Thunk/ThunkBase.h>

#define THIS_TO_STD_CODES()				\
/*	MOV ECX,m_this	*/					\
CONST	CODE_FIRST(byte,MOV_ECX,0xB9)	\
		CODE(dword_ptr,m_this,0)		\
										\
/*	JMP m_method(offset)	*/			\
CONST	CODE(byte,JMP,0xE9)				\
		CODE(dword,m_method,0)

namespace Thunk
{
	class ThisToStd
	{
	public:

		~ThisToStd();
		explicit ThisToStd(const void *Obj=0,int method=0);
		ThisToStd(const ThisToStd &src);
		ThisToStd& operator = (const ThisToStd &rhs);

		bool operator == (const ThisToStd &rhs) const;
		bool operator != (const ThisToStd &rhs) const;

		const void* Attach(const void *newObj);
		int Attach(int newMethod);
		
		template<typename Method>
		int AttachMethod(Method newMethod);

		template<typename Callback>
		Callback MakeCallback() const;

		template<typename Callback>
		operator Callback() const { return MakeCallback<Callback>(); }

	private:

		dword_ptr GetObject() const;
		void SetObject(dword_ptr newObj);

		dword GetMethod() const;
		void SetMethod(dword newMethod);
		
	private:

#pragma pack( push , 1)
		THIS_TO_STD_CODES()
#pragma pack( pop )

	};

	template<typename Method>
	int ThisToStd::AttachMethod(Method newMethod)
	{
		return Attach( Helper::PointerToInt32(newMethod) );
	}

#pragma warning( push )
#pragma warning( disable : 4311 )
	template<typename Callback>
	Callback ThisToStd::MakeCallback() const
	{
		return reinterpret_cast<Callback>( this );
	}
#pragma warning( pop )

}

#endif	//#ifndef OWN_THUNK_THIS_TO_STDCALL_H_080322
